home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-MIPS / ATOMIC.H < prev    next >
C/C++ Source or Header  |  1999-09-17  |  4KB  |  191 lines

  1. /*
  2.  * Atomic operations that C can't guarantee us.  Useful for
  3.  * resource counting etc..
  4.  *
  5.  * But use these as seldom as possible since they are much more slower
  6.  * than regular operations.
  7.  *
  8.  * This file is subject to the terms and conditions of the GNU General Public
  9.  * License.  See the file "COPYING" in the main directory of this archive
  10.  * for more details.
  11.  *
  12.  * Copyright (C) 1996, 1997 by Ralf Baechle
  13.  *
  14.  * $Id: atomic.h,v 1.4 1998/05/01 01:35:45 ralf Exp $
  15.  */
  16. #ifndef __ASM_MIPS_ATOMIC_H
  17. #define __ASM_MIPS_ATOMIC_H
  18.  
  19. #include <asm/sgidefs.h>
  20.  
  21. #ifdef __SMP__
  22. typedef struct { volatile int counter; } atomic_t;
  23. #else
  24. typedef struct { int counter; } atomic_t;
  25. #endif
  26.  
  27. #ifdef __KERNEL__
  28. #define ATOMIC_INIT(i)    { (i) }
  29.  
  30. #define atomic_read(v)    ((v)->counter)
  31. #define atomic_set(v,i)    ((v)->counter = (i))
  32.  
  33. #if (_MIPS_ISA == _MIPS_ISA_MIPS1)
  34.  
  35. #include <asm/system.h>
  36.  
  37. /*
  38.  * The MIPS I implementation is only atomic with respect to
  39.  * interrupts.  R3000 based multiprocessor machines are rare anyway ...
  40.  */
  41. extern __inline__ void atomic_add(int i, volatile atomic_t * v)
  42. {
  43.     int    flags;
  44.  
  45.     save_flags(flags);
  46.     cli();
  47.     *v += i;
  48.     restore_flags(flags);
  49. }
  50.  
  51. extern __inline__ void atomic_sub(int i, volatile atomic_t * v)
  52. {
  53.     int    flags;
  54.  
  55.     save_flags(flags);
  56.     cli();
  57.     *v -= i;
  58.     restore_flags(flags);
  59. }
  60.  
  61. extern __inline__ int atomic_add_return(int i, atomic_t * v)
  62. {
  63.     int    temp, flags;
  64.  
  65.     save_flags(flags);
  66.     cli();
  67.     temp = *v;
  68.     temp += i;
  69.     *v = temp;
  70.     restore_flags(flags);
  71.  
  72.     return temp;
  73. }
  74.  
  75. extern __inline__ int atomic_sub_return(int i, atomic_t * v)
  76. {
  77.     int    temp, flags;
  78.  
  79.     save_flags(flags);
  80.     cli();
  81.     temp = *v;
  82.     temp -= i;
  83.     *v = temp;
  84.     restore_flags(flags);
  85.  
  86.     return temp;
  87. }
  88. #endif
  89.  
  90. #if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) || \
  91.     (_MIPS_ISA == _MIPS_ISA_MIPS4) || (_MIPS_ISA == _MIPS_ISA_MIPS5)
  92. /*
  93.  * ... while for MIPS II and better we can use ll/sc instruction.  This
  94.  * implementation is SMP safe ...
  95.  */
  96.  
  97. /*
  98.  * Make sure gcc doesn't try to be clever and move things around
  99.  * on us. We need to use _exactly_ the address the user gave us,
  100.  * not some alias that contains the same information.
  101.  */
  102. #define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
  103.  
  104. extern __inline__ void atomic_add(int i, volatile atomic_t * v)
  105. {
  106.     unsigned long temp;
  107.  
  108.     __asm__ __volatile__(
  109.         "1:\tll\t%0,%1\n\t"
  110.         "addu\t%0,%2\n\t"
  111.         "sc\t%0,%1\n\t"
  112.         "beqz\t%0,1b"
  113.         :"=&r" (temp),
  114.          "=m" (__atomic_fool_gcc(v))
  115.         :"Ir" (i),
  116.          "m" (__atomic_fool_gcc(v)));
  117. }
  118.  
  119. extern __inline__ void atomic_sub(int i, volatile atomic_t * v)
  120. {
  121.     unsigned long temp;
  122.  
  123.     __asm__ __volatile__(
  124.         "1:\tll\t%0,%1\n\t"
  125.         "subu\t%0,%2\n\t"
  126.         "sc\t%0,%1\n\t"
  127.         "beqz\t%0,1b"
  128.         :"=&r" (temp),
  129.          "=m" (__atomic_fool_gcc(v))
  130.         :"Ir" (i),
  131.          "m" (__atomic_fool_gcc(v)));
  132. }
  133.  
  134. /*
  135.  * Same as above, but return the result value
  136.  */
  137. extern __inline__ int atomic_add_return(int i, atomic_t * v)
  138. {
  139.     unsigned long temp, result;
  140.  
  141.     __asm__ __volatile__(
  142.         ".set\tnoreorder\n"
  143.         "1:\tll\t%1,%2\n\t"
  144.         "addu\t%0,%1,%3\n\t"
  145.         "sc\t%0,%2\n\t"
  146.         "beqz\t%0,1b\n\t"
  147.         "addu\t%0,%1,%3\n\t"
  148.         ".set\treorder"
  149.         :"=&r" (result),
  150.          "=&r" (temp),
  151.          "=m" (__atomic_fool_gcc(v))
  152.         :"Ir" (i),
  153.          "m" (__atomic_fool_gcc(v)));
  154.  
  155.     return result;
  156. }
  157.  
  158. extern __inline__ int atomic_sub_return(int i, atomic_t * v)
  159. {
  160.     unsigned long temp, result;
  161.  
  162.     __asm__ __volatile__(
  163.         ".set\tnoreorder\n"
  164.         "1:\tll\t%1,%2\n\t"
  165.         "subu\t%0,%1,%3\n\t"
  166.         "sc\t%0,%2\n\t"
  167.         "beqz\t%0,1b\n\t"
  168.         "subu\t%0,%1,%3\n\t"
  169.         ".set\treorder"
  170.         :"=&r" (result),
  171.          "=&r" (temp),
  172.          "=m" (__atomic_fool_gcc(v))
  173.         :"Ir" (i),
  174.          "m" (__atomic_fool_gcc(v)));
  175.  
  176.     return result;
  177. }
  178. #endif
  179.  
  180. #define atomic_dec_return(v) atomic_sub_return(1,(v))
  181. #define atomic_inc_return(v) atomic_add_return(1,(v))
  182.  
  183. #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
  184. #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
  185.  
  186. #define atomic_inc(v) atomic_add(1,(v))
  187. #define atomic_dec(v) atomic_sub(1,(v))
  188. #endif /* defined(__KERNEL__) */
  189.  
  190. #endif /* __ASM_MIPS_ATOMIC_H */
  191.